package com.lanyeo.liver.task

import android.content.Context
import android.content.res.Configuration
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Point
import android.util.Log
import org.opencv.android.Utils
import org.opencv.core.Core
import org.opencv.core.Mat
import org.opencv.imgproc.Imgproc

class TaskFishing(override val context: Context) : ITask(context) {
    private var imgFishWait = Mat()
    private var imgFishGet = Mat()
    private var imgRodNoneEndurance = Mat()
    private var status = Status.START
    private var getTime = 0L
    private var waitTime = 0L
    private var pullPrecision = 20F
    private var gotPrecision = 20F
    // 检查可以拉线的次数
    private var checkNeedPullCount = 0
    private var finishCheckPullTime = 0L
    override fun initTask(onTaskTouchListener: OnTaskTouchListener?, taskParams: Any): Boolean {
        val bundlePath = context.applicationContext.getExternalFilesDir("bundle")!!.absolutePath
        Utils.bitmapToMat(BitmapFactory.decodeFile("$bundlePath/fishing/fish_get.jpg"), imgFishGet)
        val rod = Mat()
        Utils.bitmapToMat(BitmapFactory.decodeFile("$bundlePath/fishing/none_endurance.jpg"), rod)
        Imgproc.threshold(rod, imgRodNoneEndurance, 200.0, 255.0, Imgproc.THRESH_BINARY)
        pullPrecision = (taskParams as List<Float>)[0]
        gotPrecision = (taskParams)[1]
        return super.initTask(onTaskTouchListener, taskParams)
    }

    override fun doTask(screen: Bitmap, screenRotation: Int): Long {
        if (screenRotation != Configuration.ORIENTATION_LANDSCAPE) {
            return -1
        }
        setIsRunning(true)
        when (status) {
            Status.START -> {
                if (!checkRodEndurance(screen)) {
                    touch(TOUCH_EQUIPMENT_POINT.x, TOUCH_EQUIPMENT_POINT.y)
                    status = Status.SELECT_ROD
                    return nextTime(1)
                }
                touch(START_FISHING_POINT.x, START_FISHING_POINT.y)
                status = Status.WAITING
                waitTime = System.currentTimeMillis()
                return nextTime(1)
            }

            Status.SELECT_ROD -> {
                val newRodIndex = selectNewRod(screen)
                if (newRodIndex < 0) {
                    touch(TOUCH_EQUIPMENT_POINT.x, TOUCH_EQUIPMENT_POINT.y)
                    return -1
                }
                touch(Point((ROD.x - newRodIndex * EQUIPMENT_INTERVAL + 50), ROD.y + 20))
                status = Status.START
                return nextTime(1)
            }

            Status.WAITING -> {
                if (imgFishWait.empty()) {
                    Utils.bitmapToMat(Bitmap.createBitmap(screen, NEED_PULL_POINT.x, NEED_PULL_POINT.y, NEED_PULL_WIDTH, NEED_PULL_WIDTH), imgFishWait)
                }
                if (System.currentTimeMillis() - waitTime > MAX_WAIT_TIME) {
                    status = Status.FINISH
                    Log.d(TAG, "wait fish time out!")
                    return nextTime(1)
                }
                if (checkNeedPull(screen)) {
                    status = Status.FAST_CHECK
                    // 最多检测1秒
                    finishCheckPullTime = System.currentTimeMillis() + 1000
                    checkNeedPullCount++
                    return nextTime(0.25F)
                }
                return nextTime(0.5F)
            }

            Status.FAST_CHECK -> {
                if (finishCheckPullTime < System.currentTimeMillis()) {
                    status = Status.WAITING
                    checkNeedPullCount = 0
                    return nextTime(0.25F)
                }
                if (checkNeedPull(screen)) {
                    checkNeedPullCount++
                }
                if (checkNeedPullCount >= 2) {
                    status = Status.GETTING
                    getTime = System.currentTimeMillis()
                    touch(PULL_FISH_POINT.x, PULL_FISH_POINT.y)
                    return nextTime(0.25F)
                }
                return nextTime(0.25F)
            }

            Status.GETTING -> {
                touch(PULL_FISH_POINT.x, PULL_FISH_POINT.y)
                if (checkGot(screen) || System.currentTimeMillis() - getTime > MAX_GET_TIME) {
                    status = Status.FINISH
                    return nextTime(1)
                }
                return nextTime(0.15F)
            }

            Status.FINISH -> {
                status = Status.START
                imgFishWait = Mat()
                checkNeedPullCount = 0
            }
        }
        return nextTime(1)
    }

    // 检查是否可以拉起鱼竿
    private fun checkNeedPull(screen: Bitmap): Boolean {
        val mat = Mat()
        Utils.bitmapToMat(Bitmap.createBitmap(screen, NEED_PULL_POINT.x, NEED_PULL_POINT.y, imgFishWait.width(), imgFishWait.height()), mat)
        val psnr = Core.PSNR(mat, imgFishWait)
        if (psnr > 100) {
            return false
        }
        // Log.d(TAG, "checkNeedPull $psnr $pullPrecision")
        return psnr < pullPrecision
    }

    // 检查拉线
    private fun checkGot(screen: Bitmap): Boolean {
        val mat = Mat()
        Utils.bitmapToMat(Bitmap.createBitmap(screen, GET_FISH_POINT.x, GET_FISH_POINT.y, imgFishGet.width(), imgFishGet.height()), mat)
        val result = Core.PSNR(mat, imgFishGet)
        return result > gotPrecision
    }

    // 检查鱼竿是否有耐久度
    private fun checkRodEndurance(screen: Bitmap, offset: Int = 0): Boolean {
        val mat = Mat()
        Utils.bitmapToMat(Bitmap.createBitmap(screen, ROD.x - offset * EQUIPMENT_INTERVAL, ROD.y, ROD.width, ROD.height), mat)
        val binMat = Mat()
        Imgproc.threshold(mat, binMat, 200.0, 255.0, Imgproc.THRESH_BINARY)
        val psnr = Core.PSNR(binMat, imgRodNoneEndurance)
        // Log.d(TAG, "checkRodEndurance psnr:$psnr")
        return psnr < 15
    }

    // 选择新鱼竿
    private fun selectNewRod(screen: Bitmap): Int {
        for (i in 0 .. 4) {
            if (checkRodEndurance(screen, i)) {
                return i
            }
        }
        return -1
    }

    override fun finishTask() {
        status = Status.START
        setIsRunning(false)
    }

    enum class Status {
        START, SELECT_ROD, WAITING, FAST_CHECK, GETTING, FINISH
    }

    companion object {
        const val TAG = "FishingTask"
        private const val MAX_WAIT_TIME = 1000 * 60
        private const val MAX_GET_TIME = 1000 * 10

        // 点击开始钓鱼
        private val START_FISHING_POINT = Point(1830, 970)

        // 点击开始拉线
        private val PULL_FISH_POINT = Point(2000, 770)

        // 判断是否上鱼的图片的左上角
        private val GET_FISH_POINT = Point(838, 306)

        // 判断是否需要拉线的图片的左上角
        private val NEED_PULL_POINT = Point(1892, 676)
        private const val NEED_PULL_WIDTH = 207

        // 判断鱼竿耐久度的位置
        private val ROD = org.opencv.core.Rect(2104, 320, 130, 130)
        private const val EQUIPMENT_INTERVAL = 147

        private val TOUCH_EQUIPMENT_POINT = Point(2158, 500)
    }
}